#include <Windows.h>
#include "GameApp.h"
#include <OgreRenderWindow.h>
#include "MoveEvent.h"
#include "JumpEvent.h"
#include "TimeDistortionProcess.h"
#include "PauseProcess.h"
#include "MissileObject.h"

GameApp *gpApp = 0;

//-------------------------------------------------------------------------------------
GameApp::GameApp(void)
{
	gpApp = this;
	
	mpGameLogic = 0;
	mpView = 0;
	mpAudio = 0;
	mpEventManager = 0;

	mfTimeFactor = 1.0f;
	mState = State_Initializing;
}
//-------------------------------------------------------------------------------------
GameApp::~GameApp(void)
{
	delete mpInput;
	delete mpEventManager;
	delete mpAudio;
	if (mpGameLogic) delete mpGameLogic;

	mpView->removeFrameListener(this);
	Ogre::WindowEventUtilities::removeWindowEventListener(mpView->getWindow(), this);
	delete mpView;
}
//-------------------------------------------------------------------------------------
bool GameApp::initApp(void)
{
	//intizializing rand
	srand((unsigned int)time(NULL));

	// Create and initialize all game parts
	mpEventManager = new GameEventManager();

	mpAudio = new GameAudio;
	mpAudio->init();

	mpView = new GameView();
#ifdef _DEBUG 
	mpView->initView("plugins_d.cfg", "log.log", "resources.cfg");
#else 
	mpView->initView("plugins.cfg", "log.log", "resources.cfg");
#endif 

	//mpGameLogic = new GameLogic();
	//mpGameLogic->init(mpView);

	mpAudio->setListener(mpView->getCamera()->getCamera());
	mpAudio->update();
	mpAudio->setGlobalVolume(1.0f);

	// Add listener
	Ogre::WindowEventUtilities::addWindowEventListener(mpView->getWindow(), this);
	mpView->addFrameListener(this);

	// Initialize input
	mpInput = new GameInput(mpView->getWindow());

	windowResized(mpView->getWindow());

	return true;
}
//-------------------------------------------------------------------------------------
bool GameApp::startApp(void)
{
	//mState = State_Running;
	mLastTime = timeGetTime();
	//mpAudio->setBGMusic(SOUND_NERVOUSBG);
	mpView->startRendering();

	return true;
}
//-------------------------------------------------------------------------------------
bool down = false;
// This is our "main-loop"!
bool GameApp::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
	mpInput->updateInput();

	switch (mState)
	{
		case State_Initializing :
		{
			CEGUI::System::getSingleton().injectTimePulse(evt.timeSinceLastFrame);
			return true;
		}
		case State_Quitting : return false;
		case State_Starting :
		{
			mpGameLogic = new GameLogic();
			mpGameLogic->init(mpView, false);
			mLastTime = timeGetTime();
			mState = State_Running;

			return true;
		}
		case State_Loading :
		{
			mpGameLogic = new GameLogic();
			mpGameLogic->init(mpView, true);
			mLastTime = timeGetTime();
			mState = State_Running;

			return true;
		}
		case State_Reseting :
		{
			mpGameLogic->reset(true);
			mpView->getCamera()->reset();
			mLastTime = timeGetTime();
			mState = State_Running;

			return true;
		}
		case State_LoadGame :
		{
			mpGameLogic->reset(false);
			mpView->getCamera()->reset();
			mLastTime = timeGetTime();
			mState = State_Running;

			return true;
		}
		default : break;
	}

	// Pause/resume game if escape is pressed
	if (mpInput->getKeyInputs()[OIS::KC_ESCAPE].mState == JUST_PRESSED)
	{
		if (mState == State_GameOver) return true;
		if (mState == State_Pause && gpGUI->activeWindows() < 1)
		{
			mpAudio->resumeAllSounds();
			mState = State_Running;
			mLastTime = timeGetTime();
		}
		else
		{
			mpAudio->pauseAllSounds();
			mState = State_Pause;
		}
	}
	
	mpView->update(evt.timeSinceLastFrame);

	// If game is paused or its over, no updates are needed
	if (mState == State_Pause || mState == State_GameOver) return true;

	if (mpInput->getKeyInputs()[OIS::KC_A].mState == PRESSED && mpInput->getKeyInputs()[OIS::KC_D].mOrder < mpInput->getKeyInputs()[OIS::KC_A].mOrder)
		gpApp->mpEventManager->queueEvent(EventPtr(new MoveEvent(gpApp->mpGameLogic->getCharacter(), Direction_Left)));

	if (mpInput->getKeyInputs()[OIS::KC_D].mState == PRESSED && mpInput->getKeyInputs()[OIS::KC_A].mOrder < mpInput->getKeyInputs()[OIS::KC_D].mOrder)
		gpApp->mpEventManager->queueEvent(EventPtr(new MoveEvent(gpApp->mpGameLogic->getCharacter(), Direction_Right)));
	
	if ((mpInput->getMouseInputs()[OIS::MB_Right].mState == JUST_PRESSED) || (mpInput->getMouseInputs()[OIS::MB_Right].mState == PRESSED)) 
	{
		mpGameLogic->getCharacter()->block();
	}
	if (mpInput->getMouseInputs()[OIS::MB_Right].mState == JUST_RELEASED) 
	{
		mpGameLogic->getCharacter()->unblock();
	}

	if (mpInput->getMouseInputs()[OIS::MB_Left].mState == JUST_PRESSED)
	{
		if(this->mpGameLogic->getCharacter()->getSkillTree()->archetype == ARCHE_RANGED)
		{
			if(this->mpGameLogic->getCharacter()->getResources(RES_ENERGY) > 2.f)
				mpGameLogic->getCharacter()->prepareShoot();
		}
		else if(this->mpGameLogic->getCharacter()->getSkillTree()->archetype == ARCHE_MELEE)
		{
			mpGameLogic->getCharacter()->normalAttack();
		}
	}
	else if (mpInput->getMouseInputs()[OIS::MB_Left].mState == JUST_RELEASED)
	{
		if(this->mpGameLogic->getCharacter()->getSkillTree()->archetype == ARCHE_RANGED)
			mpGameLogic->getCharacter()->shoot(); 
	}
													

	if (mpInput->getKeyInputs()[OIS::KC_K].mState == PRESSED)
	{
		// This is a test-ability
		if (!down)
		{
			GameProcessPtr slow(new TimeDistortionProcess(0.98f, 0.1f));
			GameProcessPtr pause(new PauseProcess(500));
			GameProcessPtr fast(new TimeDistortionProcess(1.02f, 1.0f));

			pause->setNext(fast);
			slow->setNext(pause);

			mpGameLogic->getProcessManager()->attach(slow);

			down = true;
		}
	}

	if (mpInput->getKeyInputs()[OIS::KC_SPACE].mState == JUST_PRESSED) 
	{
		gpApp->mpEventManager->queueEvent(EventPtr(new JumpEvent(gpApp->mpGameLogic->getCharacter())));
	}
	
	// Calculate elapsed time
	unsigned long tmp = mLastTime;
	mLastTime = timeGetTime();
	unsigned long elapsedTime = mLastTime - tmp;
	elapsedTime = (unsigned long)(elapsedTime * mfTimeFactor);

	// Update everything
	mpEventManager->process(TIME_EVENT_MANAGER);
	mpGameLogic->update(elapsedTime);
	mpAudio->update();
	
	mpGameLogic->getPhysics()->getDebugDrawer()->step();

    return true;
}
//-------------------------------------------------------------------------------------
void GameApp::windowResized(Ogre::RenderWindow *rw)
{
	unsigned int width, height, depth;
    int left, top;
    rw->getMetrics(width, height, depth, left, top);

	// Adjust mouse clipping area
    const OIS::MouseState &ms = mpInput->getMouse()->getMouseState();
    ms.width = width;
    ms.height = height;

	// Adjust GUI area
	CEGUI::System::getSingleton().notifyDisplaySizeChanged(CEGUI::Size((float)width, (float)height));
}
//-------------------------------------------------------------------------------------
void GameApp::windowClosed(Ogre::RenderWindow *rw)
{
	mState = State_Quitting;
}
//-------------------------------------------------------------------------------------
GameState GameApp::getState(void) const
{
	return mState;
}
//-------------------------------------------------------------------------------------
void GameApp::changeState(GameState state)
{
	if (state == State_Running)
	{
		mLastTime = timeGetTime();
	}
	mState = state;
}
//-------------------------------------------------------------------------------------
void GameApp::setTimeFactor(const float factor)
{
	mfTimeFactor = factor;
}
//-------------------------------------------------------------------------------------
const float GameApp::getTimeFactor(void) const
{
	return mfTimeFactor;
}